// OpenGL Render
// (c) jimon game studio

#ifndef JEH_CRENDER_OPENGL
#define JEH_CRENDER_OPENGL

#include "IRender.h"
#include "CRender_OpenGL_Extensions.h"
#include "jeOpenGLSystemHeader.h"
#include "CShaderMaterial_OpenGL.h"
#include "CShaderGlobalVariable_OpenGL.h"
#include "CHardwareBuffer_OpenGL.h"
#include "CHardwareBufferArray_OpenGL.h"

#ifdef JE_RENDER_OPENGL

#include "jeOpenGLWorkMode.h"

namespace je
{
	namespace video
	{
		//! OpenGL Render
		class CRender_OpenGL:public je::video::IRender
		{
		private:
			//! Curent Render Context
			IRenderContext * CurrentContext;

			//! Current Target
			IRenderTarget * CurrentTarget;

			//! Extensions
			CRender_OpenGL_Extensions * Extensions;

			//! Projection * View * Model Matrix
			jeMatrix4f Matrix_Projection_View_Model;

			//! Normal Matrix
			jeMatrix4f Matrix_Normal;

			//! Projection * View Matrix
			jeMatrix4f Matrix_Projection_View;

			//! View * Model Matrix
			jeMatrix4f Matrix_View_Model;

			//! Projection Matrix
			jeMatrix4f Matrix_Projection;

			//! Model Matrix
			jeMatrix4f Matrix_Model;

			//! View Matrix
			jeMatrix4f Matrix_View;

			//! Texture Matrix
			jeMatrix4f Matrix_Texture;

			//! Current Material
			jeMaterial * CurrentMaterial;

			//! Global Texture Array
			ITexture ** GlobalTextures;

			//! Default Material
			jeMaterial * DefaultMaterial;

			//! Default Shader Material
			CShaderMaterial_OpenGL * DefaultShaderMaterial;

			//! Default Transparent Shader Material
			CShaderMaterial_OpenGL * DefaultTransparentShaderMaterial;

			//! Last Not Ignored Shader Material
			IShaderMaterial * LastNotIgnoredShaderMaterial;

			//! Current Shader Matrial
			CShaderMaterial_OpenGL * CurrentShaderMaterial;

			//! Last Operation Array
			CHardwareBufferArray_OpenGL * LastOperationArray;

			//! Quad Render Operation
			jeRenderOperation_Draw * QuadRenderOperation;

			//! Viewport
			s32 ViewportX;
			s32 ViewportY;
			s32 ViewportWidth;
			s32 ViewportHeight;

			//! Need Recalculate Project View Model Matrix
			u1 NeedRecalculateProjectViewModelMatrix,NeedRecalculateViewModelMatrix,NeedRecalculateNormalMatrix;

			//! Ignoring Shader Material Change
			u1 IgnoringShaderMaterialChange;

			//! Count of rendered triangles
			u32 RenderedTrianglesCount;

			//! Current Depth Mode
			DepthMode CurrentDepthMode;

			//! Shader Defines List
			CShaderMaterial_OpenGL::ShaderDefinesListType ShaderDefinesList;

			//! Create Shared Render Objects
			void CreateSharedRenderObjects();

			//! Delete Shared Render Objects
			void DeleteSharedRenderObjects();

			//! Set Matrixes To Shader Material
			void SetMatrixesToShaderMaterial();

			//! Shader Material List Type
			typedef jeList<CShaderMaterial_OpenGL*> ShaderMaterialListType;

			//! Shader Material List
			ShaderMaterialListType ShaderMaterialList;

			//! OpenGL Work Mode
			OpenGLWorkMode CurrentWorkMode;

			//! Current Shaders Global Technique
			u8 CurrentShadersGlobalTechnique;

			//! Shader Global Variables List Type
			typedef jeList<CShaderGlobalVariable_OpenGL*> ShaderGlobalVariablesListType;

			//! Shader Global Variables List
			ShaderGlobalVariablesListType ShaderGlobalVariablesList;

			//! Ignoring Material Type Change
			u1 IgnoringMaterialTypeChange;

			//! Current Force Render Operation Setup
			u1 CurrentForceRenderOperationSetup;

			//! Current Pre Render Operation Callback
			IPreRenderOperationCallback * CurrentPreRenderOperationCallback;

			//! Set Blending
			void SetBlending(MaterialType Type);
		public:
			//! Constructor
			CRender_OpenGL();

			//! Destructor
			~CRender_OpenGL();

			//! Create Texture
			ITexture * CreateTexture(IImage * Image,TextureFormat Format = TF_RGBA8,s32 Flags = TCF_DEFAULT);

			//! Create Texture
			ITexture * CreateTexture(const jeVector2di & Size,TextureFormat Format = TF_RGBA8,s32 Flags = TCF_DEFAULT);

			//! Create Texture Multisample
			ITexture * CreateTextureMultisample(const jeVector2di & Size,TextureFormat Format = TF_RGBA8,s32 Samples = 0);

			//! Create Render Buffer Texture
			//! You can use it only with RenderTargetTexture
			ITexture * CreateRenderBufferTexture(const jeVector2di & Size,TextureFormat Format = TF_RGBA8,s32 Samples = 0);

			//! Create Shader Material
			IShaderMaterial * CreateShaderMaterial(const jeStringc & Source);

			//! Set Shader Material Define
			void SetShaderMaterialDefine(const jeStringc & DefineName,const jeStringc & Define,u1 PasteCode = false);

			//! UnSet Shader Material Define
			void UnSetShaderMaterialDefine(const jeStringc & DefineName);

			//! Get Shader Material Define
			jeStringc GetShaderMaterialDefine(const jeStringc & DefineName);

			//! Recompile Shaders
			void RecompileShaders();

			//! Get Default Shader Material
			IShaderMaterial * GetDefaultShaderMaterial();

			//! Set Shaders Global Technique
			void SetShadersGlobalTechnique(u8 Technique);

			//! Get Shaders Global Technique
			u8 GetShadersGlobalTechnique();

			//! Get Global Shader Variable
			IShaderGlobalVariable * GetGlobalShaderVariable(const jeStringc & Name,u1 CreateNewInstance = false);

			//! Create Hardware Buffer
			IHardwareBuffer * CreateHardwareBuffer(Graphics3dDataType Type);

			//! Create Hardware Buffer Array
			IHardwareBufferArray * CreateHardwareBufferArray();

			//! Create Render Context
			IRenderContext * CreateContext();

			//! Set Render Context
			void SetContext(IRenderContext * Context);

			//! Get Render Context
			IRenderContext * GetContext();

			//! Create Texture Render Traget
			IRenderTargetTexture * CreateTextureRenderTarget();

			//! Set Render Target
			void SetTarget(IRenderTarget * RenderTarget);

			//! Get Render Target
			IRenderTarget * GetTarget();

			//! Begin
			void Begin();

			//! End
			void End();

			//! Clear Screen
			void ClearScreen(const jeColorARGB32f & Color);

			//! Clear Depth
			void ClearDepth();

			//! Set Viewport
			void SetViewport(u1 UseContextSize = true,s32 X = 0,s32 Y = 0,s32 Width = 0,s32 Height = 0);

			//! Get Viewport Position
			jeVector2di GetViewportPosition();

			//! Get Viewport Size
			jeVector2di GetViewportSize();

			//! Render Operation
			void RenderOperation(RenderOperationType Type,jeRenderOperation * Data = NULL);

			//! Set Pre Render Operation Callback
			void SetPreRenderOperationCallback(IPreRenderOperationCallback * Callback);

			//! Get Pre Render Operation Callback
			IPreRenderOperationCallback * GetPreRenderOperationCallback();

			//! Set Force Render Operation Setup
			void SetForceRenderOperationSetup(u1 Enabled);

			//! Get Force Render Operation Setup
			u1 GetForceRenderOperationSetup();

			//! Set Matrix
			void SetMatrix(const jeMatrix4f & Matrix,RenderMatrixType Type);

			//! Get Matrix
			const jeMatrix4f & GetMatrix(RenderMatrixType Type);

			//! Set Material
			void SetMaterial(jeMaterial * Material);

			//! Get Material
			jeMaterial * GetMaterial();

			//! Get Default Material
			jeMaterial * GetDefaultMaterial();

			//! Get Currently Used Shader Material
			IShaderMaterial * GetCurrentlyUsedShaderMaterial();

			//! Enable Ignoring Shader Material Change
			void EnableIgnoringShaderMaterialChange(u1 Enable);

			//! Set Global Texture
			void SetGlobalTexture(ITexture * Texture,s32 TextureLayer);

			//! Set Global Material Type
			void SetGlobalMaterialType(u1 Enable,MaterialType Type = MT_SOLID);

			//! Set Depth Mode
			void SetDepthMode(DepthMode Mode);

			//! Get Depth Mode
			DepthMode GetDepthMode();

			//! Copy Framebuffer to texture
			void CopyFrameBufferToTexture(ITexture * Texture,jeVector2di Start,jeVector2di WidthHeight);

			//! Get Rendered Triangles Count
			u32 GetRenderedTrianglesCount();

			//! Remove Shader Material
			void RemoveShaderMaterial(IShaderMaterial * Material);

			//! Remove Global Shader Variable
			void RemoveGlobalShaderVariable(IShaderVariable * Variable);
		};
	}
}

#endif
#endif
